package com.learn.sb.redis.reids.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 测试 使用Spring boot配置文件 application.properties
 * 测试 string, hash, list, zset用法s
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisDataStructDemo {

	@Autowired
	private RedisTemplate redisTemplate;

	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	// 定义 后初始化 方法
	@PostConstruct
	public void init() {
		initRedisTemplate();
	}
	private void initRedisTemplate() {
		RedisSerializer stringRedisSerializer = redisTemplate.getStringSerializer();
		redisTemplate.setDefaultSerializer(stringRedisSerializer); // 不设这这个写入redis就默认使用jdkSerializer
	}

	// 操作字符串
	@Test
	public void useStringRedisTemplate() {
		stringRedisTemplate.opsForValue().set("int", "1");
		stringRedisTemplate.opsForValue().increment("int", 5);
	}

	// 直接使用Jedis操作
	@Test
	public void useJedis() {
		Jedis jedis = (Jedis) stringRedisTemplate.getConnectionFactory().getConnection().getNativeConnection();
		jedis.decr("int"); // 减 1 操作
	}

	// 使用 hash
	@Test
	public void saveHashMap() {
		Map<String, String> map = new HashMap<>();
		map.put("field1", "value1");
		map.put("field2", "value2");
		map.put("field3", "value3");
		stringRedisTemplate.opsForHash().putAll("hashDemo3", map);
		stringRedisTemplate.opsForHash().put("hashDemo3", "field4", "value4");
	}
	@Test
	public void useBoundHashOperations() {
		BoundHashOperations hashOps = stringRedisTemplate.boundHashOps("hashDemo3");
		hashOps.delete("field1");
		hashOps.put("field4", "value5");
	}

	// 使用list
	@Test
	public void useListAsQueue() {
		stringRedisTemplate.opsForList().leftPushAll("list1", "v2", "v3", "v4");
		stringRedisTemplate.opsForList().rightPushAll("list2", "v1", "v5", "v6");
	}
	@Test
	public void useListAsQueue2() {
		BoundListOperations listOps = stringRedisTemplate.boundListOps("list2");
		String s1 = String.valueOf(listOps.rightPop());
		System.out.println("s1 ==>" + s1);
		String s2 = String.valueOf(listOps.index(1));
		System.out.println("s2 ==>" + s2);
		listOps.leftPush("v0");
		Long size = listOps.size();
		System.out.println("size ==>" + size);
		List elems = listOps.range(0, size);

		StringJoiner sj = new StringJoiner(",");
		elems.stream().forEach(elem -> sj.add(String.valueOf(elem)));
		System.out.println(sj.toString());
	}

	// 使用有序结合 zset
	@Test
	public void testZset() {
		Set<ZSetOperations.TypedTuple<String>> typedTupleSet = new HashSet<>();
		for(int i=1; i<=9; ++i) {
			double score = i*0.1;
			ZSetOperations.TypedTuple<String> typedTuple = new DefaultTypedTuple<>("value" + i, score);
			typedTupleSet.add(typedTuple);
		}
		stringRedisTemplate.opsForZSet().add("zset1", typedTupleSet);
	}
	@Test
	public void testBoundZset() {
		BoundZSetOperations zsetOps = stringRedisTemplate.boundZSetOps("zset1");
		zsetOps.add("value11", 0.26);
		Set<String> setRange = zsetOps.range(1,6);

		String str = setRange.stream().collect(Collectors.joining(", ")).toString();
		System.out.println("11=>" + str);
		Set<String> setScore = zsetOps.rangeByScore(0.2, 0.6);
		str = setScore.stream().collect(Collectors.joining(", ")).toString();
		System.out.println("22=>" + str);

//		RedisZSetCommands.Range range = new RedisZSetCommands.Range();
//		range.gt("value3");
//		range.lte("value8");
//		// 按值排序，请注意这个排序 是 按 字符串排序
//		Set<String> setLex = zsetOps.rangeByLex(range);
//		str = setLex.stream().collect(Collectors.joining(", ")).toString();
//		System.out.println("33=>" + str);

		// 删除元素
		zsetOps.remove("value9", "value2");
		// 求分数
		Double score = zsetOps.score("value8");
		// 在 下标区间下，按分数排序，同时返回 value 和 score
		Set<ZSetOperations.TypedTuple<String>> rangeSet = zsetOps.rangeWithScores(1, 6);
		StringJoiner sj = new StringJoiner("; ");
		rangeSet.stream().forEach(item -> sj.add(item.getValue() + "=>" + item.getScore()));
		System.out.println("44=>" + sj);

		// 在 分数区间下，按分数排序，同时返回 value 和 score
		Set<ZSetOperations.TypedTuple<String>> scoreSet = zsetOps.rangeByScoreWithScores(1, 6);
		StringJoiner sj2 = new StringJoiner("; ");
		scoreSet.stream().forEach(item -> sj2.add(item.getValue() + "=>" + item.getScore()));
		System.out.println("55=>" + sj2);

		// 按从大到小排序
		Set<String> reverseSet = zsetOps.reverseRange(2, 8);
		System.out.println("66=>" + reverseSet.stream().collect(Collectors.joining(", ")));

	}
}
